home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / port / ultrix4 / dynloader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  6.7 KB  |  267 lines

  1.  
  2. /*
  3.  *  $Header: /private/postgres/src/port/ultrix4/RCS/dynloader.c,v 1.20 1992/05/27 16:31:22 mao Exp $
  4.  */
  5.  
  6.  
  7. /*
  8.  * New dynamic loader.
  9.  *
  10.  * How does this work?  Glad you asked :-)
  11.  *
  12.  * In the DEC dynamic loader, we have to have done the following in order
  13.  * for it to work:
  14.  *
  15.  * 1. Make sure that we stay near & etext (the highest base text address)
  16.  *    so that we do not try to jump into the data area.  The data area starts
  17.  *    by default at 0x1000000.
  18.  *
  19.  * 2. Make sure everything is linked with the -N option, so that "ld -A" will
  20.  *    do the right thing.
  21.  *
  22.  * 3. Make sure loaded objects are compiled with "-G 0"
  23.  *
  24.  * 4. Make sure loaded objects are loaded ONCE AND ONLY ONCE.
  25.  *
  26.  * The algorithm is as follows:
  27.  *
  28.  * 1.  Find out how much text/data space will be required.  This is done
  29.  *     by reading the header of the ".o" to be loaded.
  30.  *
  31.  * 2.  Execute the "ld -A" with a an address equal to some memory we malloc'ed.
  32.  *     "ld -A" will do all the relocation, etc. for us.
  33.  *
  34.  * 3.  Using the output of "ld -A", read the text and data area into a valid
  35.  *     text area.  (The DEC 3100 allows data to be read in the text area, but
  36.  *     not vice versa.)
  37.  * 
  38.  * 4.  Determine which functions are defined by the object file we are loading,
  39.  *     and using the address we loaded the output of "ld -A" into, find the
  40.  *     addresses of those functions.  In object files, the symbol table (and 
  41.  *     the output of nm) will give the offsets for functions.  Adding the
  42.  *     function offset to the base text address gives the function's true
  43.  *     address.  (This could also be done by reading the symbol table of the
  44.  *     output of "ld -A", but it is so massive that this is VERY wasteful.)
  45.  * 
  46.  *     (In this case, we cheat rather hugely and use the output of nm because
  47.  *     the symbol table format for MIPSEL/DS3100 is not well-documented).
  48.  */ 
  49.  
  50. #include <stdio.h>
  51. #include <sys/types.h>
  52. #include <sys/param.h>
  53. #include <sys/stat.h>
  54. #include <sys/file.h>
  55.  
  56. #include <a.out.h>
  57. #include <symconst.h>
  58. #include <mips/cachectl.h>
  59.  
  60. #include "tmp/c.h"
  61. #include "utils/fmgr.h"
  62.  
  63. extern char pg_pathname[];
  64.  
  65. static char *load_address = NULL;
  66. static char *temp_file_name = NULL;
  67. static char *path = "/usr/tmp/postgresXXXXXX";
  68.  
  69. #define PAGE_ROUND(X) ((X) % 512 == 0 ? (X) : (X) - (X) % 512 + 512)
  70.  
  71. DynamicFunctionList *
  72. dynamic_file_load(err, filename, start_addr, size)
  73.  
  74. char **err, *filename, **start_addr;
  75. long *size;
  76.  
  77. {
  78.     extern etext, edata, end;
  79.     extern char *mktemp();
  80.  
  81.     int nread;
  82.     char command[256];
  83.     unsigned long image_size, true_image_size;
  84.     FILE *temp_file = NULL;
  85.     DynamicFunctionList *retval = NULL, *load_symbols();
  86.     struct filehdr obj_file_struct, ld_file_struct;
  87.     AOUTHDR obj_aout_hdr, ld_aout_hdr;
  88.     struct scnhdr scn_struct;
  89.     int size_text, size_data = 0, size_bss = 0, bss_offset;
  90.     int i, fd;
  91.  
  92.     fd = open(filename, O_RDONLY);
  93.  
  94.     read(fd, & obj_file_struct, sizeof(struct filehdr));
  95.     read(fd, & obj_aout_hdr, sizeof(AOUTHDR));
  96.  
  97.     read(fd, & scn_struct, sizeof(struct scnhdr)); /* text hdr */
  98.     size_text = scn_struct.s_size;
  99.     if (obj_file_struct.f_nscns > 1)
  100.     {
  101.         read(fd, & scn_struct, sizeof(struct scnhdr)); /* data hdr */
  102.         size_data = scn_struct.s_size;
  103.     }
  104.  
  105.     close(fd);
  106.  
  107. /*
  108.  * add 10000 for fudge factor to account for data areas that appear in
  109.  * the linking process (yes, there are such beasts!).
  110.  */
  111.  
  112.     image_size = size_text + size_data + 10000;
  113.  
  114.     if (temp_file_name == NULL)
  115.     {
  116.         temp_file_name = (char *)malloc(strlen(path) + 1);
  117.     }
  118.  
  119.     strcpy(temp_file_name,path);
  120.     mktemp(temp_file_name);
  121.  
  122.     load_address = (char *) valloc(image_size);
  123.  
  124.     sprintf(command,"ld -x -N -A %s -T %lx -o %s  %s -lc -lm -ll",
  125.         pg_pathname,
  126.         load_address,
  127.         temp_file_name,  filename);
  128.  
  129.     if (system(command))
  130.     {
  131.         *err = "link failed!";
  132.         goto finish_up;
  133.     }
  134.  
  135.     if(!(temp_file = fopen(temp_file_name,"r")))
  136.     {
  137.         *err = "unable to open tmp file";
  138.         goto finish_up;
  139.     }
  140.     fread(&ld_file_struct, sizeof(struct filehdr), 1, temp_file);
  141.     fread(&ld_aout_hdr, sizeof(AOUTHDR), 1, temp_file);
  142.  
  143.     fread(&scn_struct, sizeof(struct scnhdr), 1, temp_file); /* text hdr */
  144.  
  145. /*
  146.  * Figure out how big the data areas (including the bss area) are,
  147.  * and determine where the bss area is if there is one.
  148.  */
  149.  
  150.     true_image_size = scn_struct.s_size;
  151.     for (i = 1; i < ld_file_struct.f_nscns; i++)
  152.     {
  153.         fread(&scn_struct, sizeof(struct scnhdr), 1, temp_file);
  154.         true_image_size += scn_struct.s_size;
  155.         if (!strcmp(scn_struct.s_name, "bss"))
  156.         {
  157.             size_bss = scn_struct.s_size;
  158.             bss_offset = scn_struct.s_vaddr - (int) load_address;
  159.         }
  160.     }
  161.  
  162. /*
  163.  * Here we see if our "fudge guess" above was too small.  We do it this way
  164.  * because loading is so ungodly expensive, and we want to avoid having to
  165.  * create 3 megabyte files unnecessarily.
  166.  */
  167.  
  168.     if (true_image_size > image_size)
  169.     {
  170.         free(load_address);
  171.         fclose(temp_file);
  172.         unlink(temp_file_name);
  173.         load_address = (char *) valloc(true_image_size);
  174.         sprintf(command,"ld -x -N -A %s -T %lx -o %s  %s -lc -lm -ll",
  175.                 pg_pathname,
  176.                 load_address,
  177.                 temp_file_name,  filename);
  178.         system(command);
  179.         temp_file = fopen(temp_file_name,"r");
  180.         fread(&ld_file_struct, sizeof(struct filehdr), 1, temp_file);
  181.         fread(&ld_aout_hdr, sizeof(AOUTHDR), 1, temp_file);
  182.     }
  183.  
  184.     fseek(temp_file, N_TXTOFF(ld_file_struct, ld_aout_hdr), 0);
  185.  
  186.     fread(load_address, true_image_size,1,temp_file);
  187.  
  188.     /* zero the BSS segment */
  189.  
  190.     if (size_bss != 0)
  191.     {
  192.         bzero(bss_offset + load_address, size_bss);
  193.     }
  194.  
  195.     if (cachectl(load_address, PAGE_ROUND(true_image_size), UNCACHEABLE))
  196.     {
  197.         *err = "dynamic_file_load: Cachectl failed!";
  198.     }
  199.     else
  200.     {
  201.         retval = load_symbols(filename, load_address);
  202.     }
  203.  
  204. finish_up:
  205.     fclose(temp_file);
  206.     unlink(temp_file_name);
  207.     *start_addr = load_address;
  208.     *size = true_image_size;
  209.     return retval;
  210. }
  211.  
  212. /*
  213.  * Cheat massively because I can't figure out how to read the symbol table
  214.  * properly, so use system("nm ...") to do it instead.
  215.  */
  216.  
  217. DynamicFunctionList *
  218. load_symbols(filename, entry_addr)
  219.  
  220. char *filename;
  221. int entry_addr;
  222.  
  223. {
  224.     char command[256];
  225.     char line[128];
  226.     char *tmp_file = "/tmp/PG_DYNSTUFF";
  227.     FILE *fp;
  228.     DynamicFunctionList *head, *scanner;
  229.     int entering = 1, func_addr;
  230.     char funcname[16];
  231.  
  232.     sprintf(command, "/usr/bin/nm %s | grep \' T \' > %s", filename, tmp_file);
  233.  
  234.     if (system(command))
  235.     {
  236.         fprintf(stderr, "system() died\n");
  237.     }
  238.  
  239.     fp = fopen(tmp_file, "r");
  240.  
  241.     while (fgets(line, 127, fp) != NULL)
  242.     {
  243.         sscanf(line, "%lx T %s", &func_addr, funcname);
  244.         if (entering)
  245.         {
  246.             head = (DynamicFunctionList *)
  247.                    malloc(sizeof(DynamicFunctionList));
  248.             scanner = head;
  249.             entering = 0;
  250.         }
  251.         else
  252.         {
  253.             scanner->next = (DynamicFunctionList *)
  254.                             malloc(sizeof(DynamicFunctionList));
  255.             scanner = scanner->next;
  256.         }
  257.  
  258.         strncpy(scanner->funcname, funcname, 16);
  259.         scanner->func = (func_ptr) (func_addr + entry_addr);
  260.         scanner->next = NULL;
  261.     }
  262.  
  263.     fclose(fp);
  264.     unlink(tmp_file);
  265.     return(head);
  266. }
  267.